home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmiSoft / Util / Sys / Amberram.lha / AmberRAM / Source / filesystem.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-29  |  26.8 KB  |  1,359 lines

  1. /*
  2.  
  3. File: filesystem.c
  4. Author: Neil Cafferkey
  5. Copyright (C) 2001-2003 Neil Cafferkey
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  20. MA 02111-1307, USA.
  21.  
  22. */
  23.  
  24.  
  25. #include "handler_protos.h"
  26.  
  27.  
  28. static struct Block *AddDataBlock(struct Handler *handler,
  29.    struct Object *file,UPINT length);
  30. static VOID FreeDataBlock(struct Object *file,struct Block *block);
  31. static struct Block *GetLastBlock(struct Object *file);
  32.  
  33.  
  34.  
  35. /****i* ram.handler/CreateObject *******************************************
  36. *
  37. *   NAME
  38. *    CreateObject --
  39. *
  40. *   SYNOPSIS
  41. *    object = CreateObject(handler,name,type,
  42. *        parent)
  43. *
  44. *    struct Object *CreateObject(struct Handler *,TEXT *,BYTE,
  45. *        struct Object *);
  46. *
  47. *   FUNCTION
  48. *    Creates a new filesystem object. The existence of a duplicate object
  49. *    must be checked for beforehand.
  50. *
  51. *   INPUTS
  52. *    name - The name of the new object, without a path prefixed.
  53. *    type - The type of object to create.
  54. *    parent - The new object's parent directory, or NULL for none.
  55. *
  56. *   RESULT
  57. *    object - The newly created object, or NULL for failure.
  58. *
  59. *   EXAMPLE
  60. *
  61. *   NOTES
  62. *
  63. *   BUGS
  64. *
  65. *   SEE ALSO
  66. *
  67. ****************************************************************************
  68. *
  69. */
  70.  
  71. struct Object *CreateObject(struct Handler *handler,const TEXT *name,
  72.    BYTE type,struct Object *parent)
  73. {
  74.    struct Object *object=NULL;
  75.    LONG error=0;
  76.  
  77.    /* Get the real parent in case it's a hard link */
  78.  
  79.    if(parent!=NULL)
  80.       parent=GetRealObject(parent);
  81.  
  82.    /* Create a new object structure */
  83.  
  84.    object=AllocMem(sizeof(struct Object),MEMF_CLEAR);
  85.    if(object==NULL)
  86.       error=ERROR_DISK_FULL;
  87.  
  88.    if(error==0)
  89.    {
  90.       object->block_count=MEMBLOCKS(sizeof(struct Object));
  91.       handler->block_count+=MEMBLOCKS(sizeof(struct Object));
  92.  
  93.       NewList((struct List *)&object->elements);
  94.       ((struct Node *)object)->ln_Pri=type;
  95.       object->parent=parent;
  96.       DateStamp(&object->date);
  97.       NewList((struct List *)&object->notifications);
  98.  
  99.       if(name!=NULL)
  100.       {
  101.          if(!SetName(handler,object,name))
  102.             error=IoErr();
  103.       }
  104.  
  105.       if(parent!=NULL)
  106.       {
  107.          AddTail((struct List *)&parent->elements,(struct Node *)object);
  108.          CopyMem(&object->date,&parent->date,sizeof(struct DateStamp));
  109.       }
  110.    }
  111.  
  112.    if(error==0)
  113.       MatchNotifyRequests(handler);
  114.  
  115.    if(error!=0)
  116.    {
  117.       DeleteObject(handler,object);
  118.       object=NULL;
  119.    }
  120.  
  121.    /* Return the new object */
  122.  
  123.    SetIoErr(error);
  124.    return object;
  125. }
  126.  
  127.  
  128.  
  129. /****i* ram.handler/AttemptDeleteObject ************************************
  130. *
  131. *   NAME
  132. *    AttemptDeleteObject --
  133. *
  134. *   SYNOPSIS
  135. *    success = AttemptDeleteObject(handler,object)
  136. *
  137. *    BOOL AttemptDeleteObject(struct Handler *,struct Object *);
  138. *
  139. *   FUNCTION
  140. *
  141. *   INPUTS
  142. *    object - the object to be deleted, or NULL for no action.
  143. *
  144. *   RESULT
  145. *    success - success indicator.
  146. *
  147. *   EXAMPLE
  148. *
  149. *   NOTES
  150. *
  151. *   BUGS
  152. *
  153. *   SEE ALSO
  154. *
  155. ****************************************************************************
  156. *
  157. */
  158.  
  159. BOOL AttemptDeleteObject(struct Handler *handler,struct Object *object)
  160. {
  161.    LONG error=0;
  162.    BYTE object_type;
  163.    struct Lock *lock;
  164.  
  165.    if(object!=NULL)
  166.    {
  167.       /* Check for a non-empty, unlinked directory */
  168.  
  169.       object_type=((struct Node *)object)->ln_Pri;
  170.       if((object_type==ST_USERDIR)&&(object->hard_link.mln_Succ==NULL)
  171.          &&!IsListEmpty((struct List *)&object->elements))
  172.          error=ERROR_DIRECTORY_NOT_EMPTY;
  173.  
  174.       /* Ensure the object isn't in use */
  175.  
  176.       lock=LockObject(handler,object,ACCESS_WRITE);
  177.       if(lock==NULL)
  178.          error=IoErr();
  179.       CmdFreeLock(handler,lock);
  180.  
  181.       /* Delete object and notify anyone who's interested */
  182.  
  183.       if(error==0)
  184.       {
  185.          NotifyAll(handler,object,FALSE);
  186.          UnmatchNotifyRequests(handler,object);
  187.          DeleteObject(handler,object);
  188.       }
  189.    }
  190.  
  191.    /* Return result */
  192.  
  193.    SetIoErr(error);
  194.    return error==0;
  195. }
  196.  
  197.  
  198.  
  199. /****i* ram.handler/DeleteObject *******************************************
  200. *
  201. *   NAME
  202. *    DeleteObject --
  203. *
  204. *   SYNOPSIS
  205. *    success = DeleteObject(handler,object)
  206. *
  207. *    BOOL DeleteObject(struct Handler *,struct Object *);
  208. *
  209. *   FUNCTION
  210. *
  211. *   INPUTS
  212. *    object - the object to be deleted, or NULL for no action.
  213. *
  214. *   RESULT
  215. *    None.
  216. *
  217. *   EXAMPLE
  218. *
  219. *   NOTES
  220. *
  221. *   BUGS
  222. *
  223. *   SEE ALSO
  224. *
  225. ****************************************************************************
  226. *
  227. */
  228.  
  229. VOID DeleteObject(struct Handler *handler,struct Object *object)
  230. {
  231.    BYTE object_type;
  232.    struct Block *block;
  233.    struct MinNode *node;
  234.    struct Object *real_object,*master_link,*heir,*dir;
  235.    PINT block_diff;
  236.  
  237.    if(object!=NULL)
  238.    {
  239.       object_type=((struct Node *)object)->ln_Pri;
  240.       real_object=GetRealObject(object);
  241.  
  242.       /* Remove the object from its directory */
  243.  
  244.       if(object->parent!=NULL)
  245.          Remove((struct Node *)object);
  246.  
  247.       /* Delete a hard link */
  248.  
  249.       if((object_type==ST_LINKFILE)||(object_type==ST_LINKDIR))
  250.       {
  251.          node=real_object->hard_link.mln_Succ;
  252.          master_link=HARDLINK(node);
  253.          node=node->mln_Succ;
  254.          Remove((APTR)&object->hard_link);
  255.          if(object==master_link)
  256.          {
  257.             if(node->mln_Succ!=NULL)
  258.             {
  259.                master_link=HARDLINK(node);
  260.                while((node=(APTR)RemHead((APTR)&object->elements))!=NULL)
  261.                   AddTail((APTR)&master_link->elements,(APTR)node);
  262.             }
  263.             else
  264.             {
  265.                real_object->hard_link.mln_Succ=NULL;
  266.                real_object->hard_link.mln_Pred=NULL;
  267.             }
  268.          }
  269.       }
  270.  
  271.       /* Delete a linked object */
  272.  
  273.       else if((node=object->hard_link.mln_Succ)!=NULL)
  274.       {
  275.          master_link=HARDLINK(node);
  276.          heir=HARDLINK(RemTail((APTR)&master_link->elements));
  277.  
  278.          /* Swap names and comments */
  279.  
  280.          block_diff=SwapStrings(&((struct Node *)heir)->ln_Name,
  281.             &((struct Node *)object)->ln_Name);
  282.          block_diff+=SwapStrings(&heir->comment,&object->comment);
  283.          object->block_count+=block_diff;
  284.          heir->block_count-=block_diff;
  285.  
  286.          /* Put object in its new directory */
  287.  
  288.          object->parent=heir->parent;
  289.          AddTail((APTR)&object->parent->elements,(APTR)object);
  290.  
  291.          if(heir==master_link)
  292.          {
  293.             real_object->hard_link.mln_Succ=NULL;
  294.             real_object->hard_link.mln_Pred=NULL;
  295.          }
  296.  
  297.          /* Prepare to destroy "heir" link */
  298.  
  299.          Remove((APTR)heir);
  300.          object=heir;
  301.       }
  302.  
  303.       /* Delete the root directory and all other objects */
  304.  
  305.       else if(object_type==ST_ROOT)
  306.       {
  307.          dir=object;
  308.  
  309.          while(dir!=NULL)
  310.          {
  311.             object=(APTR)RemHead((struct List *)&dir->elements);
  312.  
  313.             if(object==NULL)
  314.             {
  315.                object=dir;
  316.                dir=dir->parent;
  317.                if(dir!=NULL)
  318.                   DeleteObject(handler,object);
  319.             }
  320.             else if(((struct Node *)object)->ln_Pri==ST_USERDIR)
  321.             {
  322.                dir=object;
  323.             }
  324.             else
  325.             {
  326.                DeleteObject(handler,object);
  327.             }
  328.          }
  329.       }
  330.  
  331.       /* Delete an unlinked object */
  332.  
  333.       else
  334.       {
  335.          /* Remove all blocks if the object is a file */
  336.  
  337.          while((block=(APTR)RemTail((struct List *)&object->elements))
  338.             !=NULL)
  339.             FreeMem(block,sizeof(struct Block)+block->length);
  340.       }
  341.  
  342.       /* Free object's memory */
  343.  
  344.       SetString(&((struct Node *)object)->ln_Name,NULL);
  345.       SetString(&object->comment,NULL);
  346.       handler->block_count-=object->block_count;
  347.       FreeMem(object,sizeof(struct Object));
  348.    }
  349.  
  350.    return;
  351. }
  352.  
  353.  
  354.  
  355. /****i* ram.handler/GetObject **********************************************
  356. *
  357. *   NAME
  358. *    GetObject --
  359. *
  360. *   SYNOPSIS
  361. *    object = GetObject(handler,lock,name,
  362. *        parent)
  363. *
  364. *    struct Object *GetObject(struct Handler *,struct Lock *,TEXT *,
  365. *        struct Object **);
  366. *
  367. *   FUNCTION
  368. *
  369. *   INPUTS
  370. *    lock - .
  371. *    name - .
  372. *    parent - .
  373. *
  374. *   RESULT
  375. *    object - The located object.
  376. *
  377. *   EXAMPLE
  378. *
  379. *   NOTES
  380. *
  381. *   BUGS
  382. *
  383. *   SEE ALSO
  384. *
  385. ****************************************************************************
  386. *
  387. */
  388.  
  389. struct Object *GetObject(struct Handler *handler,
  390.    struct Lock *lock,const TEXT *name,struct Object **parent)
  391. {
  392.    const TEXT *p;
  393.    TEXT ch,buffer[256];
  394.    PINT pos;
  395.    struct Object *object,*old_object;
  396.  
  397.    old_object=NULL;
  398.    for(ch=*(p=name);(ch!=':')&&(ch!='\0');ch=*(++p));
  399.    if(ch==':')
  400.       name=p+1;
  401.  
  402.    /* Get object referenced by lock */
  403.  
  404.    lock=FixLock(handler,lock);
  405.    object=(APTR)((struct FileLock *)lock)->fl_Key;
  406.  
  407.    /* Traverse textual portion of path */
  408.  
  409.    pos=0;
  410.    while((pos!=-1)&&(object!=NULL))
  411.    {
  412.       pos=SplitName(name,'/',buffer,pos,256);
  413.       if(*buffer!='\0')
  414.       {
  415.          old_object=object;
  416.          if(((struct Node *)object)->ln_Pri>0)
  417.          {
  418.             object=GetRealObject(object);
  419.             object=(struct Object *)
  420.                FindNameNoCase((struct List *)&object->elements,buffer);
  421.          }
  422.          else
  423.          {
  424.             object=NULL;
  425.             old_object=NULL;
  426.          }
  427.       }
  428.       else if(pos!=-1)
  429.       {
  430.          object=object->parent;
  431.       }
  432.    }
  433.  
  434.    /* Record the parent directory of the supplied path, if it exists */
  435.  
  436.    if(parent!=NULL)
  437.    {
  438.       if(pos==-1)
  439.          *parent=old_object;
  440.       else
  441.          *parent=NULL;
  442.    }
  443.  
  444.    /* Return the located object */
  445.  
  446.    SetIoErr(ERROR_OBJECT_NOT_FOUND);
  447.    return object;
  448. }
  449.  
  450.  
  451.  
  452. /****i* ram.handler/ChangeFileSize *****************************************
  453. *
  454. *   NAME
  455. *    ChangeFileSize --
  456. *
  457. *   SYNOPSIS
  458. *    new_size = ChangeFileSize(handler,opening,offset,
  459. *       mode)
  460. *
  461. *    PINT ChangeFileSize(struct Handler *,struct Opening *,PINT,
  462. *       LONG);
  463. *
  464. *   FUNCTION
  465. *    If there is not enough space for the requested size, the file size
  466. *    will remain at its initial value and -1 will be returned.
  467. *
  468. *
  469. *
  470. *
  471. *   INPUTS
  472. *
  473. *   RESULT
  474. *
  475. *   EXAMPLE
  476. *
  477. *   NOTES
  478. *
  479. *   BUGS
  480. *
  481. *   SEE ALSO
  482. *
  483. ****************************************************************************
  484. *
  485. */
  486.  
  487. PINT ChangeFileSize(struct Handler *handler,struct Opening *opening,
  488.    PINT offset,LONG mode)
  489. {
  490.    PINT length,new_length,remainder,end_length,full_length;
  491.    UPINT diff,old_pos,block_count;
  492.    struct Block *block,*end_block;
  493.    struct Object *file;
  494.    LONG error=0;
  495.  
  496.    /* Get origin */
  497.  
  498.    file=opening->file;
  499.  
  500.    if(mode==OFFSET_BEGINNING)
  501.       new_length=0;
  502.    else if(mode==OFFSET_CURRENT)
  503.       new_length=opening->pos;
  504.    else
  505.       new_length=file->length;
  506.  
  507.    /* Check new size won't be negative */
  508.  
  509.    if(-offset>new_length)
  510.    {
  511.       SetIoErr(ERROR_SEEK_ERROR);
  512.       return -1;
  513.    }
  514.  
  515.    /* Get new length */
  516.  
  517.    new_length+=offset;
  518.    length=file->length;
  519.    block_count=file->block_count;
  520.  
  521.    /* Get full length (including any unused area in last block) */
  522.  
  523.    old_pos=opening->pos;
  524.    full_length=length;
  525.    end_length=file->end_length;
  526.  
  527.    block=GetLastBlock(file);
  528.    if(block!=NULL)
  529.       full_length+=block->length-end_length;
  530.  
  531.    /* Change size */
  532.  
  533.    if(new_length>length)
  534.    {
  535.       /* Add the required number of data bytes */
  536.  
  537.       remainder=new_length-full_length;
  538.       end_length-=remainder;
  539.  
  540.       while(remainder>0)
  541.       {
  542.          block=AddDataBlock(handler,file,remainder);
  543.          if(block!=NULL)
  544.          {
  545.             end_length=remainder;
  546.             remainder-=block->length;
  547.          }
  548.          else
  549.             remainder=0;
  550.       }
  551.  
  552.       /* Remove new blocks upon failure */
  553.  
  554.       if(block==NULL)
  555.       {
  556.          new_length=-1;
  557.          error=IoErr();
  558.          ChangeFileSize(handler,opening,length,OFFSET_BEGINNING);
  559.       }
  560.       else
  561.          file->end_length=end_length;
  562.    }
  563.    else if(length!=new_length)
  564.    {
  565.       /* Remove surplus blocks from the file */
  566.  
  567.       block=NULL;
  568.       while(full_length>new_length)
  569.       {
  570.          FreeDataBlock(file,block);
  571.          block=(APTR)RemTail((APTR)&file->elements);
  572.          full_length-=block->length;
  573.       }
  574.       end_block=(APTR)file->elements.mlh_TailPred;
  575.       if((APTR)end_block!=(APTR)&file->elements)
  576.          end_length=end_block->length;
  577.       else
  578.          end_length=0;
  579.       file->end_length=end_length;
  580.  
  581.       /* Allocate a suitably sized end block and copy old data to it */
  582.  
  583.       diff=new_length-full_length;
  584.       file->length=full_length;
  585.       CmdSeek(opening,0,OFFSET_END);
  586.  
  587.       if(ChangeFileSize(handler,opening,diff,OFFSET_END)!=-1)
  588.       {
  589.          WriteData(handler,opening,((UBYTE *)block)+sizeof(struct Block),
  590.             diff);
  591.          FreeDataBlock(file,block);
  592.       }
  593.       else
  594.          AddTail((struct List *)&file->elements,(APTR)block);
  595.  
  596.       /* Ensure opening's position isn't past new EOF */
  597.  
  598.       if(opening->pos>new_length)
  599.       {
  600.          opening->block=(APTR)&file->elements.mlh_Tail;
  601.          opening->block_pos=0;
  602.          opening->pos=new_length;
  603.       }
  604.    }
  605.  
  606.    /* Re-establish old seek position */
  607.  
  608.    CmdSeek(opening,old_pos,OFFSET_BEGINNING);
  609.  
  610.    /* Store new file size */
  611.  
  612.    if(new_length!=-1)
  613.       file->length=new_length;
  614.    handler->block_count+=file->block_count-block_count;
  615.  
  616.    SetIoErr(error);
  617.    return new_length;
  618. }
  619.  
  620.  
  621.  
  622. /****i* ram.handler/ReadData ***********************************************
  623. *
  624. *   NAME
  625. *    ReadData --
  626. *
  627. *   SYNOPSIS
  628. *    read_length = ReadData(opening,buffer,length)
  629. *
  630. *    UPINT ReadData(struct Opening *,UBYTE *,UPINT);
  631. *
  632. *   FUNCTION
  633. *
  634. *   INPUTS
  635. *
  636. *   RESULT
  637. *
  638. *   EXAMPLE
  639. *
  640. *   NOTES
  641. *
  642. *   BUGS
  643. *
  644. *   SEE ALSO
  645. *
  646. ****************************************************************************
  647. *
  648. */
  649.  
  650. UPINT ReadData(struct Opening *opening,UBYTE *buffer,UPINT length)
  651. {
  652.    struct Block *block;
  653.    UPINT block_pos,block_length,read_length=0,remainder;
  654.    struct Object *file;
  655.  
  656.    /* Fill buffer until request has been fulfilled or EOF is reached */
  657.  
  658.    block=opening->block;
  659.    block_pos=opening->block_pos;
  660.    file=opening->file;
  661.  
  662.    remainder=file->length-opening->pos;
  663.    if(length>remainder)
  664.       length=remainder;
  665.    remainder=length;
  666.  
  667.    while(remainder>0)
  668.    {
  669.       /* Get number of remaining valid bytes in this block */
  670.  
  671.       block_length=GetBlockLength(file,block);
  672.       block_length-=block_pos;
  673.  
  674.       /* Copy block contents into the caller's buffer */
  675.  
  676.       read_length=MIN(remainder,block_length);
  677.       CopyMem(((UBYTE *)block)+sizeof(struct Block)+block_pos,buffer,
  678.          read_length);
  679.       remainder-=read_length;
  680.       buffer+=read_length;
  681.  
  682.       /* Get next block */
  683.  
  684.       if(read_length==block_length)
  685.       {
  686.          block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  687.          block_pos=0;
  688.          read_length=0;
  689.       }
  690.    }
  691.  
  692.    /* Record new position for next access */
  693.  
  694.    opening->block=block;
  695.    opening->block_pos=block_pos+read_length;
  696.    opening->pos+=length;
  697.  
  698.    /* Return number of bytes read */
  699.  
  700.    return length;
  701. }
  702.  
  703.  
  704.  
  705. /****i* ram.handler/WriteData **********************************************
  706. *
  707. *   NAME
  708. *    WriteData --
  709. *
  710. *   SYNOPSIS
  711. *    write_length = WriteData(handler,opening,buffer,length)
  712. *
  713. *    UPINT WriteData(struct Handler *,struct Opening *,UBYTE *,UPINT);
  714. *
  715. *   FUNCTION
  716. *
  717. *   INPUTS
  718. *
  719. *   RESULT
  720. *
  721. *   EXAMPLE
  722. *
  723. *   NOTES
  724. *
  725. *   BUGS
  726. *
  727. *   SEE ALSO
  728. *
  729. ****************************************************************************
  730. *
  731. */
  732.  
  733. UPINT WriteData(struct Handler *handler,struct Opening *opening,
  734.    UBYTE *buffer,UPINT length)
  735. {
  736.    struct Block *block,*end_block;
  737.    struct Object *file;
  738.    UPINT block_pos,block_length,write_length,remainder=length,
  739.       old_block_count,file_length,pos;
  740.    LONG error=0;
  741.  
  742.    file=opening->file;
  743.    file_length=file->length;
  744.    old_block_count=file->block_count;
  745.    pos=opening->pos;
  746.    block=opening->block;
  747.    block_pos=opening->block_pos;
  748.  
  749.    /* If at EOF, go back to use up any space left in last block */
  750.  
  751.    if((pos==file_length)&&(pos!=0))
  752.    {
  753.       block=(struct Block *)((struct MinNode *)block)->mln_Pred;
  754.       block_pos=file->end_length;
  755.    }
  756.  
  757.    while((remainder>0)&&(block!=NULL)&&(error==0))
  758.    {
  759.       /* Add another block to the file if required */
  760.  
  761.       if(((struct MinNode *)block)->mln_Succ==NULL)
  762.       {
  763.          block=AddDataBlock(handler,opening->file,remainder);
  764.          if(block!=NULL)
  765.             file->end_length=0;
  766.       }
  767.  
  768.       /* Write as much as possible to the current block */
  769.  
  770.       if(block!=NULL)
  771.       {
  772.          block_length=block->length-block_pos;
  773.          write_length=MIN(remainder,block_length);
  774.          CopyMem(buffer,((UBYTE *)block)+sizeof(struct Block)+block_pos,
  775.             write_length);
  776.          remainder-=write_length;
  777.          buffer+=write_length;
  778.          block_pos+=write_length;
  779.  
  780.          /* Move on to next block if end of current block reached */
  781.  
  782.          if(write_length==block_length)
  783.          {
  784.             block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  785.             block_pos=0;
  786.          }
  787.       }
  788.       else
  789.          error=IoErr();
  790.    }
  791.  
  792.    /* Recalculate length of used portion of last block */
  793.  
  794.    end_block=GetLastBlock(file);
  795.    if(end_block!=NULL)
  796.    {
  797.       if((block==end_block)&&(block_pos>=file->end_length))
  798.       {
  799.          file->end_length=block_pos;
  800.          block=(struct Block *)((struct MinNode *)block)->mln_Succ;
  801.          block_pos=0;
  802.       }
  803.       else if(((struct MinNode *)block)->mln_Succ==NULL)
  804.          file->end_length=end_block->length;
  805.    }
  806.  
  807.    /* Update file size, volume size and current position */
  808.  
  809.    length-=remainder;
  810.    pos+=length;
  811.    if(pos>file_length)
  812.       file->length=pos;
  813.    opening->pos=pos;
  814.    opening->block=block;
  815.    opening->block_pos=block_pos;
  816.    handler->block_count+=file->block_count-old_block_count;
  817.  
  818.    /* Return number of bytes written */
  819.  
  820.    SetIoErr(error);
  821.    return length;
  822. }
  823.  
  824.  
  825.  
  826. /****i* ram.handler/LockObject *********************************************
  827. *
  828. *   NAME
  829. *    LockObject --
  830. *
  831. *   SYNOPSIS
  832. *    lock = LockObject(handler,object,
  833. *        access)
  834. *
  835. *    struct Lock *LockObject(struct Handler *handler,struct Object *,
  836. *        LONG);
  837. *
  838. *   FUNCTION
  839. *
  840. *   INPUTS
  841. *
  842. *   RESULT
  843. *
  844. *   EXAMPLE
  845. *
  846. *   NOTES
  847. *
  848. *   BUGS
  849. *
  850. *   SEE ALSO
  851. *
  852. ****************************************************************************
  853. *
  854. */
  855.  
  856. struct Lock *LockObject(struct Handler *handler,struct Object *object,
  857.    LONG access)
  858. {
  859.    struct Lock *lock;
  860.    LONG error,lock_access;
  861.  
  862.    object=GetRealObject(object);
  863.    lock=object->lock;
  864.  
  865.    if(lock==NULL)
  866.    {
  867.       lock=AllocMem(sizeof(struct Lock),MEMF_PUBLIC|MEMF_CLEAR);
  868.  
  869.       if(lock!=NULL)
  870.       {
  871.          object->lock=lock;
  872.  
  873.          ((struct FileLock *)lock)->fl_Key=(PINT)object;
  874.          ((struct FileLock *)lock)->fl_Access=access;
  875.          ((struct FileLock *)lock)->fl_Task=handler->proc_port;
  876.          ((struct FileLock *)lock)->fl_Volume=MKBADDR(handler->volume);
  877.       }
  878.       else
  879.          error=IoErr();
  880.    }
  881.    else
  882.    {
  883.       lock_access=((struct FileLock *)lock)->fl_Access;
  884.       if((access==ACCESS_WRITE)||(lock_access==ACCESS_WRITE))
  885.       {
  886.          lock=NULL;
  887.          error=ERROR_OBJECT_IN_USE;
  888.       }
  889.    }
  890.  
  891.    if(lock!=NULL)
  892.    {
  893.       lock->lock_count++;
  894.       handler->lock_count++;
  895.    }
  896.  
  897.    SetIoErr(error);
  898.  
  899.    return lock;
  900. }
  901.  
  902.  
  903.  
  904. /****i* ram.handler/ExamineObject ******************************************
  905. *
  906. *   NAME
  907. *    ExamineObject --
  908. *
  909. *   SYNOPSIS
  910. *    success = ExamineObject(handler,object,
  911. *        info)
  912. *
  913. *    BOOL ExamineObject(struct Handler *,struct Object *,
  914. *        struct FileInfoBlock *);
  915. *
  916. *   FUNCTION
  917. *
  918. *   INPUTS
  919. *
  920. *   RESULT
  921. *
  922. *   EXAMPLE
  923. *
  924. *   NOTES
  925. *
  926. *   BUGS
  927. *
  928. *   SEE ALSO
  929. *
  930. ****************************************************************************
  931. *
  932. */
  933.  
  934. BOOL ExamineObject(struct Handler *handler,struct Object *object,
  935.    struct FileInfoBlock *info)
  936. {
  937.    BOOL success;
  938.    struct Object *next_object;
  939.    STRPTR s;
  940.    LONG entry_type;
  941.  
  942.    if(object==NULL)
  943.    {
  944.       object=(struct Object *)info->fib_DiskKey;
  945.       next_object=(APTR)((struct Node *)object)->ln_Succ;
  946.    }
  947.    else
  948.       next_object=(APTR)object->elements.mlh_Head;
  949.  
  950.    if(next_object!=NULL)
  951.    {
  952.       /* Fill in information from object */
  953.  
  954.       entry_type=((struct Node *)object)->ln_Pri;
  955.       info->fib_DirEntryType=entry_type;
  956.       info->fib_EntryType=entry_type;
  957.       s=((struct Node *)object)->ln_Name;
  958.       CopyMem(MkBStr(s),&info->fib_FileName,StrSize(s));
  959.       s=object->comment;
  960.       if(s!=NULL)
  961.          CopyMem(MkBStr(s),&info->fib_Comment,StrLen(s)+1);
  962.       else
  963.          info->fib_Comment[0]='\0';
  964.       info->fib_NumBlocks=object->block_count;
  965.  
  966.       /* Fill in information from real object */
  967.  
  968.       object=GetRealObject(object);
  969.  
  970.       info->fib_Protection=object->protection;
  971.       info->fib_Size=object->length;
  972.       CopyMem(&object->date,&info->fib_Date,sizeof(struct DateStamp));
  973.  
  974.       /* Prepare for next examination */
  975.  
  976.       success=TRUE;
  977.       info->fib_DiskKey=(PINT)next_object;
  978.    }
  979.    else
  980.    {
  981.       success=FALSE;
  982.       SetIoErr(ERROR_NO_MORE_ENTRIES);
  983.    }
  984.  
  985.    return success;
  986. }
  987.  
  988.  
  989.  
  990. /****i* ram.handler/SetName ************************************************
  991. *
  992. *   NAME
  993. *    SetName --
  994. *
  995. *   SYNOPSIS
  996. *    success = SetName(handler,object,name)
  997. *
  998. *    BOOL SetName(struct Handler *,struct Object *,TEXT *);
  999. *
  1000. *   FUNCTION
  1001. *
  1002. *   INPUTS
  1003. *
  1004. *   RESULT
  1005. *
  1006. *   EXAMPLE
  1007. *
  1008. *   NOTES
  1009. *
  1010. *   BUGS
  1011. *
  1012. *   SEE ALSO
  1013. *
  1014. ****************************************************************************
  1015. *
  1016. */
  1017.  
  1018. BOOL SetName(struct Handler *handler,struct Object *object,
  1019.    const TEXT *name)
  1020. {
  1021.    LONG error;
  1022.    const TEXT *p;
  1023.    TEXT ch;
  1024.    struct Locale *locale;
  1025.    PINT block_diff;
  1026.  
  1027.    error=0;
  1028.  
  1029.    /* Check name isn't too long */
  1030.  
  1031.    if(StrSize(name)>sizeof(((struct FileInfoBlock *)NULL)->fib_FileName))
  1032.       error=ERROR_INVALID_COMPONENT_NAME;
  1033.  
  1034.    /* Check name doesn't have any strange characters in it */
  1035.  
  1036.    locale=handler->locale;
  1037.    for(p=name;(ch=*p)!='\0';p++)
  1038.       if(!IsPrint(locale,ch)||IsCntrl(locale,ch)||(ch==':'))
  1039.          error=ERROR_INVALID_COMPONENT_NAME;
  1040.  
  1041.    /* Store new name */
  1042.  
  1043.    if(error==0)
  1044.    {
  1045.       block_diff=SetString(&((struct Node *)object)->ln_Name,name);
  1046.       error=IoErr();
  1047.    }
  1048.  
  1049.    if(error==0)
  1050.    {
  1051.       object->block_count+=block_diff;
  1052.       handler->block_count+=block_diff;
  1053.    }
  1054.  
  1055.    /* Return success indicator */
  1056.  
  1057.    SetIoErr(error);
  1058.    return error==0;
  1059. }
  1060.  
  1061.  
  1062.  
  1063. /****i* ram.handler/FixLock ************************************************
  1064. *
  1065. *   NAME
  1066. *    FixLock --
  1067. *
  1068. *   SYNOPSIS
  1069. *    fixed_lock = FixLock(handler,lock)
  1070. *
  1071. *    struct Lock *FixLock(struct Handler *,struct Lock *);
  1072. *
  1073. *   FUNCTION
  1074. *
  1075. *   INPUTS
  1076. *
  1077. *   RESULT
  1078. *
  1079. *   EXAMPLE
  1080. *
  1081. *   NOTES
  1082. *
  1083. *   BUGS
  1084. *
  1085. *   SEE ALSO
  1086. *
  1087. ****************************************************************************
  1088. *
  1089. */
  1090.  
  1091. struct Lock *FixLock(struct Handler *handler,struct Lock *lock)
  1092. {
  1093.    if(lock==NULL)
  1094.       lock=handler->root_dir->lock;
  1095.  
  1096.    return lock;
  1097. }
  1098.  
  1099.  
  1100.  
  1101. /****i* ram.handler/AddDataBlock *******************************************
  1102. *
  1103. *   NAME
  1104. *    AddDataBlock --
  1105. *
  1106. *   SYNOPSIS
  1107. *    block = AddDataBlock(file,length)
  1108. *
  1109. *    struct Block *AddDataBlock(struct Object *,UPINT);
  1110. *
  1111. *   FUNCTION
  1112. *
  1113. *   INPUTS
  1114. *
  1115. *   RESULT
  1116. *
  1117. *   EXAMPLE
  1118. *
  1119. *   NOTES
  1120. *    Attempts to allocate a smaller block if the requested size cannot be
  1121. *    obtained.
  1122. *
  1123. *   BUGS
  1124. *
  1125. *   SEE ALSO
  1126. *
  1127. ****************************************************************************
  1128. *
  1129. */
  1130.  
  1131. static struct Block *AddDataBlock(struct Handler *handler,
  1132.    struct Object *file,UPINT length)
  1133. {
  1134.    struct Block *block;
  1135.    UPINT alloc_size;
  1136.    ULONG limit;
  1137.  
  1138.    /* Ensure block size is within limits */
  1139.  
  1140.    alloc_size=sizeof(struct Block)+length;
  1141.  
  1142.    limit=handler->max_block_size;
  1143.    if(alloc_size>limit)
  1144.       alloc_size=limit;
  1145.  
  1146.    limit=handler->min_block_size;
  1147.    if(alloc_size<limit)
  1148.       alloc_size=limit;
  1149.  
  1150.    /* Allocate a multiple of the memory block size */
  1151.  
  1152.    block=NULL;
  1153.    while((block==NULL)&&(alloc_size>=limit))
  1154.    {
  1155.       alloc_size=((alloc_size-1)&(~MEM_BLOCKMASK))+MEM_BLOCKSIZE;
  1156.       block=AllocMem(alloc_size,MEMF_ANY);
  1157.       if(block==NULL)
  1158.          alloc_size>>=1;
  1159.    }
  1160.  
  1161.    /* Add the block to the end of the file */
  1162.  
  1163.    if(block!=NULL)
  1164.    {
  1165.       AddTail((struct List *)&file->elements,(struct Node *)block);
  1166.       block->length=alloc_size-sizeof(struct Block);
  1167.       file->block_count+=alloc_size>>MEM_BLOCKSHIFT;
  1168.    }
  1169.    else
  1170.       SetIoErr(ERROR_DISK_FULL);
  1171.  
  1172.    /* Return the new block */
  1173.  
  1174.    return block;
  1175. }
  1176.  
  1177.  
  1178.  
  1179. /****i* ram.handler/FreeDataBlock ******************************************
  1180. *
  1181. *   NAME
  1182. *    FreeDataBlock --
  1183. *
  1184. *   SYNOPSIS
  1185. *    FreeDataBlock(file,block)
  1186. *
  1187. *    VOID FreeDataBlock(struct Object *,struct Block *);
  1188. *
  1189. *   FUNCTION
  1190. *
  1191. *   INPUTS
  1192. *
  1193. *   RESULT
  1194. *
  1195. *   EXAMPLE
  1196. *
  1197. *   NOTES
  1198. *
  1199. *   BUGS
  1200. *
  1201. *   SEE ALSO
  1202. *
  1203. ****************************************************************************
  1204. *
  1205. */
  1206.  
  1207. static VOID FreeDataBlock(struct Object *file,struct Block *block)
  1208. {
  1209.    UPINT alloc_size;
  1210.  
  1211.    if(block!=NULL)
  1212.    {
  1213.       alloc_size=sizeof(struct Block)+block->length;
  1214.       file->block_count-=alloc_size>>MEM_BLOCKSHIFT;
  1215.       FreeMem(block,alloc_size);
  1216.    }
  1217.  
  1218.    return;
  1219. }
  1220.  
  1221.  
  1222.  
  1223. /****i* ram.handler/GetRealObject ******************************************
  1224. *
  1225. *   NAME
  1226. *    GetRealObject --
  1227. *
  1228. *   SYNOPSIS
  1229. *    real_object = GetRealObject(object)
  1230. *
  1231. *    struct Object *GetRealObject(struct Object *);
  1232. *
  1233. *   FUNCTION
  1234. *
  1235. *   INPUTS
  1236. *
  1237. *   RESULT
  1238. *
  1239. *   EXAMPLE
  1240. *
  1241. *   NOTES
  1242. *
  1243. *   BUGS
  1244. *
  1245. *   SEE ALSO
  1246. *
  1247. ****************************************************************************
  1248. *
  1249. */
  1250.  
  1251. struct Object *GetRealObject(struct Object *object)
  1252. {
  1253.    struct MinNode *node,*pred;
  1254.  
  1255.    /* Get first node in list */
  1256.  
  1257.    node=&object->hard_link;
  1258.    if(node->mln_Pred!=NULL)
  1259.    {
  1260.       while((pred=node->mln_Pred)!=NULL)
  1261.          node=pred;
  1262.       node=node->mln_Succ;
  1263.    }
  1264.  
  1265.    /* Get object from node address */
  1266.  
  1267.    object=HARDLINK(node);
  1268.    return object;
  1269. }
  1270.  
  1271.  
  1272.  
  1273. /****i* ram.handler/GetBlockLength *****************************************
  1274. *
  1275. *   NAME
  1276. *    GetBlockLength --
  1277. *
  1278. *   SYNOPSIS
  1279. *    length = GetBlockLength(file,block)
  1280. *
  1281. *    UPINT GetBlockLength(struct Object *,struct Block *);
  1282. *
  1283. *   FUNCTION
  1284. *
  1285. *   INPUTS
  1286. *
  1287. *   RESULT
  1288. *
  1289. *   EXAMPLE
  1290. *
  1291. *   NOTES
  1292. *
  1293. *   BUGS
  1294. *
  1295. *   SEE ALSO
  1296. *
  1297. ****************************************************************************
  1298. *
  1299. */
  1300.  
  1301. UPINT GetBlockLength(struct Object *file,struct Block *block)
  1302. {
  1303.    UPINT length;
  1304.  
  1305.    if(block==(APTR)file->elements.mlh_TailPred)
  1306.       length=file->end_length;
  1307.    else if(((struct MinNode *)block)->mln_Succ==NULL)
  1308.       length=0;
  1309.    else
  1310.       length=block->length;
  1311.  
  1312.    return length;
  1313. }
  1314.  
  1315.  
  1316.  
  1317. /****i* ram.handler/GetLastBlock *******************************************
  1318. *
  1319. *   NAME
  1320. *    GetLastBlock --
  1321. *
  1322. *   SYNOPSIS
  1323. *    block = GetLastBlock(file)
  1324. *
  1325. *    struct Block *GetLastBlock(struct Object *);
  1326. *
  1327. *   FUNCTION
  1328. *
  1329. *   INPUTS
  1330. *
  1331. *   RESULT
  1332. *
  1333. *   EXAMPLE
  1334. *
  1335. *   NOTES
  1336. *
  1337. *   BUGS
  1338. *
  1339. *   SEE ALSO
  1340. *
  1341. ****************************************************************************
  1342. *
  1343. */
  1344.  
  1345. static struct Block *GetLastBlock(struct Object *file)
  1346. {
  1347.    struct Block *block;
  1348.  
  1349.    if(IsListEmpty((struct List *)&file->elements))
  1350.       block=NULL;
  1351.    else
  1352.       block=(APTR)file->elements.mlh_TailPred;
  1353.  
  1354.    return block;
  1355. }
  1356.  
  1357.  
  1358.  
  1359.